package com.xfzcode.service.impl;

import com.xfzcode.pojo.CommonEntity;
import com.xfzcode.service.ElasticsearchDocumentService;
import com.xfzcode.utils.SearchTools;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.ScoreSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.elasticsearch.search.suggest.phrase.PhraseSuggestion;
import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder;
import org.elasticsearch.search.suggest.term.TermSuggestion;
import org.elasticsearch.search.suggest.term.TermSuggestionBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Author XMLee
 * @Date 2022年08月11日 22:46
 * @Description:
 */
@Service
public class ElasticsearchDocumentServiceImpl implements ElasticsearchDocumentService {


    @Resource
    private RestHighLevelClient client;

    /**
     * 全文检索
     *
     * @param commonEntity
     * @return
     * @throws Exception
     */
    @Override
    public SearchResponse matchQuery(CommonEntity commonEntity) throws Exception {

        //构建查询响应
        SearchResponse response = null;
        //构建查询请求，用于搜索文档
        SearchRequest searchRequest = new SearchRequest(commonEntity.getIndexName());
        //构建请求体，trackTotalHits如果不设置true，查询数据最大值还是10000
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().trackTotalHits(true);
        //获取前端查询条件
        getClientConditions(commonEntity, searchSourceBuilder);
        //高亮设置
        searchSourceBuilder.highlighter(SearchTools.getHighlightBuilder(commonEntity.getHighlight()));
        //前端页码
        int pageNumber = commonEntity.getPageNumber();
        //前端每页显示数量
        int pageSize = commonEntity.getPageSize();
        //计算下标
        int dest = (pageNumber - 1) * pageSize;
        searchSourceBuilder.from(dest);
        //每页数量
        searchSourceBuilder.size(pageSize);
        //查询条件对象放入到请求对象中
        searchRequest.source(searchSourceBuilder);
        //执行远程查询
        response = client.search(searchRequest, RequestOptions.DEFAULT);
        //处理高亮
        SearchTools.setHighResultForCleintUI(response, commonEntity.getHighlight());
        return response;
    }

    /**
     * 结构话搜索--->类似jd的导航栏搜索
     *
     * @param commonEntity
     * @return
     */
    @Override
    public SearchResponse termQuery(CommonEntity commonEntity) throws Exception {
        SearchResponse response = null;
        //构建查询请求
        //查询的索引
        SearchRequest searchRequest = new SearchRequest(commonEntity.getIndexName());
        //构建DSL请求体
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().trackTotalHits(true);
        XContentParser xContentParser = SearchTools.getXContentParser(commonEntity);
        searchSourceBuilder.parseXContent(xContentParser);
        //高亮设置
        searchSourceBuilder.highlighter(SearchTools.getHighlightBuilder(commonEntity.getHighlight()));
        //前端页码
        int pageNumber = commonEntity.getPageNumber();
        //前端每页显示数量
        int pageSize = commonEntity.getPageSize();
        //计算下标
        int dest = (pageNumber - 1) * pageSize;
        searchSourceBuilder.from(dest);
        //每页数量
        searchSourceBuilder.size(pageSize);
        //排序
        sort(commonEntity, searchSourceBuilder);
        //查询条件对象放入到请求对象中
        searchRequest.source(searchSourceBuilder);
        //执行远程查询
        response = client.search(searchRequest, RequestOptions.DEFAULT);
        //处理高亮
        SearchTools.setHighResultForCleintUI(response, commonEntity.getHighlight());
        return response;

    }

    //自动补全
    @Override
    public List<String> cSuggest(CommonEntity commonEntity) throws Exception {
        ArrayList<String> suggestList = new ArrayList<>();
        //创建自动补全构建器
        CompletionSuggestionBuilder completionSuggestionBuilder = SuggestBuilders.completionSuggestion(commonEntity.getSuggestFileld());
        //搜索关键字
        completionSuggestionBuilder.prefix(commonEntity.getSuggestValue());
        //是否去重
        completionSuggestionBuilder.skipDuplicates(true);
        //数量匹配
        completionSuggestionBuilder.size(commonEntity.getSuggestCount());
        //执行查询操作
        SearchRequest searchRequest = new SearchRequest().indices(commonEntity.getIndexName()).source(new SearchSourceBuilder().sort(new ScoreSortBuilder().order(SortOrder.DESC))
                .suggest(new SuggestBuilder().addSuggestion("xfzcode-suggest", completionSuggestionBuilder)));
        //定义查询响应
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        //定义完成建议对象
        CompletionSuggestion completionSuggestion = searchResponse.getSuggest().getSuggestion("xfzcode-suggest");
        //获取返回的数据
        List<CompletionSuggestion.Entry.Option> optionList = completionSuggestion.getEntries().get(0).getOptions();

        if (!CollectionUtils.isEmpty(optionList)) {
            optionList.forEach(option -> {
                suggestList.add(option.getText().toString());
            });
        }
        return suggestList;
    }

    //批量导入
    @Override
    public RestStatus bulkAndDoc(CommonEntity commonEntity) throws Exception {
        BulkRequest bulkRequest = new BulkRequest(commonEntity.getIndexName());
        //循环前台的参数信息
        for (int i = 0; i < commonEntity.getList().size(); i++) {
            bulkRequest.add(new IndexRequest().source(XContentType.JSON, SearchTools.mapToObjectGroup(commonEntity.getList().get(i))));
        }
        //执行批量信息操作
        BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        return bulkResponse.status();
    }

    //自动纠错
    @Override
    public String parseSuggest(CommonEntity commonEntity) throws Exception {
        //定义返回结果
        String pSuggestString = new String();
        //创建短语构建器对象
        PhraseSuggestionBuilder phraseSuggestionBuilder = new PhraseSuggestionBuilder(commonEntity.getSuggestFileld());
        //设置关键字
        phraseSuggestionBuilder.text(commonEntity.getSuggestValue());
        //设置匹配数量
        phraseSuggestionBuilder.size(1);
        //执行查询操作
        SearchRequest searchRequest = new SearchRequest().indices(commonEntity.getIndexName()).source(new SearchSourceBuilder().sort(new ScoreSortBuilder().order(SortOrder.DESC))
                .suggest(new SuggestBuilder().addSuggestion("xfzcode-suggest", phraseSuggestionBuilder)));
        //定义查询响应
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        //定义完成建议对象
        PhraseSuggestion phraseSuggestion = searchResponse.getSuggest().getSuggestion("xfzcode-suggest");
        //获取返回的数据
        List<PhraseSuggestion.Entry.Option> optionList = phraseSuggestion.getEntries().get(0).getOptions();

        //处理结果
        if (!CollectionUtils.isEmpty(optionList)) {
            pSuggestString = optionList.get(0).getText().string();
        }

        return pSuggestString;
    }

    /**
     * 搜索推荐，根据用户搜索的关键字进行推荐搜索
     * @param commonEntity
     * @return
     * @throws Exception
     */
    @Override
    public String tSuggest(CommonEntity commonEntity) throws Exception {
        //定义返回
        String tSuggestString=new String();
        //创建词条构建器
        TermSuggestionBuilder termSuggestionBuilder=SuggestBuilders.termSuggestion(commonEntity.getSuggestFileld());
        //定义搜索关键字
        termSuggestionBuilder.text(commonEntity.getSuggestValue());
        //设置分词
        termSuggestionBuilder.analyzer("ik_smart");
        //设置搜索关键字长度
        termSuggestionBuilder.minWordLength(2);
        //定义字符串查找算法
        termSuggestionBuilder.stringDistance(TermSuggestionBuilder.StringDistanceImpl.NGRAM);
        //执行查询操作
        SearchRequest searchRequest = new SearchRequest().indices(commonEntity.getIndexName()).source(new SearchSourceBuilder().sort(new ScoreSortBuilder().order(SortOrder.DESC
        )).suggest(new SuggestBuilder().addSuggestion("xfzcode-suggest", termSuggestionBuilder)));
        //定义查询响应
        SearchResponse searchResponse=client.search(searchRequest,RequestOptions.DEFAULT);
        //定义完成建议对象
        TermSuggestion termSuggestion=searchResponse.getSuggest().getSuggestion("xfzcode-suggest");
        //定义List返回数据
        TermSuggestion.Entry options = termSuggestion.getEntries().get(0);
        if (options != null) {
            tSuggestString  = options.getText().toString();
        }
        return tSuggestString;

        /*List<TermSuggestion.Entry.Option> optionList=termSuggestion.getEntries().get(0).getOptions();
        if(!CollectionUtils.isEmpty(optionList)){
            tSuggestString=optionList.get(0).getText().toString();
        }

        return tSuggestString;*/

    }

    private void sort(CommonEntity commonEntity, SearchSourceBuilder searchSourceBuilder) {
        String sortField = commonEntity.getSortField();
        if (StringUtils.isNotEmpty(sortField)) {
            //获取sortOrder
            SortOrder sortOrder = SearchTools.getSortOrder(commonEntity.getSortOrder());
            //执行排序
            searchSourceBuilder.sort(new FieldSortBuilder(sortField).order(sortOrder));
        }
    }

    private void getClientConditions(CommonEntity commonEntity, SearchSourceBuilder searchSourceBuilder) {
        //循环前端参数
        for (Map.Entry<String, Object> m : commonEntity.getMap().entrySet()) {
            if (StringUtils.isNotEmpty(m.getKey()) && m.getValue() != null) {
                String key = m.getKey();
                String value = String.valueOf(m.getValue());
                //构造请求体query
                searchSourceBuilder.query(QueryBuilders.matchQuery(key, value));
            }
        }
    }

}
